#pragma once
#include <string>
#include <map>
#include <windows.h>
#include <vector>
#include "test_report.h"

#include "widgets.h"

namespace krryn{
namespace test{
	class widget_win32{
	public:
		HWND hWnd;
		virtual void notify(WPARAM, LPARAM) {};
	};

	class helper_win32{
	public:
		// returns the objects ID
		static HMENU register_object(widget_win32 *a_widget);
		static void dispatch(WPARAM wParam, LPARAM lParam);
		static NONCLIENTMETRICS *get_non_client_metrics();
		static void update_font(HWND hWnd);
		static void set_size(HWND hWnd, int a_Width, int a_Height);
		static void set_position(HWND hWnd, int a_Width, int a_Height);
	private:
		static NONCLIENTMETRICS *m_NonClientMetrics;
		static std::map<int, widget_win32*> m_widgets;
		static int m_CurrentWidgetId;
	};

	class window_win32 : public widget_win32, public gui::window{
	public:
		window_win32();
		static LRESULT CALLBACK wnd_proc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam);
		virtual void add_child(widget *a_Child){}
		virtual void do_layout();

		virtual gui::button *create_button();
		virtual gui::progress_bar *create_progress_bar();
		virtual gui::tree_view *create_tree_view();

		virtual void set_caption(const std::string &a_Text);
		virtual void set_size(int a_Width, int a_Height);
		virtual void set_position(int a_X, int a_Y);
		virtual void show();
	private:
		std::string m_Title;
	};

	class button_win32 : public widget_win32, public gui::button{
	public:
		button_win32(widget *a_Parent);
		virtual void notify(WPARAM, LPARAM);
		virtual void do_layout();

		virtual void set_caption(const std::string &a_Text);
		virtual void set_size(int a_Width, int a_Height);
		virtual void set_position(int a_X, int a_Y);
	};

	class progress_bar_win32 : public widget_win32, public gui::progress_bar{
	public:
		progress_bar_win32(widget *a_Parent);
		virtual void do_layout();
		virtual void set_size(int a_Width, int a_Height);
		virtual void set_position(int a_X, int a_Y);
		virtual void set_range(int a_Begin, int a_End);
		virtual void set_progress(int a_Progress);
	};

	class tree_view_node_win32;
	class tree_view_win32 : public widget_win32, public gui::tree_view{
	public:
		tree_view_win32(widget *a_Parent);
		
		virtual void do_layout();
		virtual void set_size(int a_Width, int a_Height);
		virtual void set_position(int a_X, int a_Y);

		virtual void add_node(gui::tree_view_node *a_Node, const std::string &a_ParentKey = "");
	private:
		std::map<std::string, tree_view_node_win32 *> m_Nodes;
	};

	class test_report_window : public gui::window{
	public:
		test_report_window() : gui::window() {}

		virtual void init(){
			gui::button *l_ButtonOk = create_button();
			l_ButtonOk->set_caption("OK");
			l_ButtonOk->set_position(530, 10);
			l_ButtonOk->set_size(90, 22);

			l_ButtonOk->m_OnClick += bind(this, &test_report_window::buttonok_click);
			add_child(l_ButtonOk);

			m_Progress = create_progress_bar();
			m_Progress->set_position(10, 10);
			m_Progress->set_size(500, 22);
			add_child(m_Progress);

			m_TreeView = create_tree_view();
			m_TreeView->set_position(10, 42);
			m_TreeView->set_size(605, 590);

			m_TreeView->add_node(new gui::tree_view_node("root", "Root"));
			m_TreeView->add_node(new gui::tree_view_node("child_1", "child 1"), "root");
			m_TreeView->add_node(new gui::tree_view_node("child_1.1", "child 1.1"), "child_1");
			m_TreeView->add_node(new gui::tree_view_node("child_2", "child 2"), "root");

			add_child(m_TreeView);

			set_size(640, 680);
			set_caption("krryn::test");
		}

		void group(const std::string &a_GroupName){
			m_TreeView->add_node(new gui::tree_view_node(a_GroupName, a_GroupName));
		}

		void failure(const std::string &a_GroupName, const std::string &a_Failure){
			m_TreeView->add_node(new gui::tree_view_node(a_Failure, a_Failure), a_GroupName);
		}

		void buttonok_click(core::basic_args *a_Args){
			exit(1);
		}

		void set_max_tests(size_t a_Maximum){
			m_Progress->set_range(0, (int)a_Maximum);
		}

		void set_progress(int a_Progress){
			m_Progress->set_progress(a_Progress);
		}
	private:
		gui::progress_bar *m_Progress;
		gui::tree_view *m_TreeView;
	};

	class test_report_win32 : public basic_report{
	public:
		test_report_win32(){
			// do this in different thread
			DWORD l_Temp;
			m_MaxTotal = 0;
			m_Progress = 0;
			m_Id = ::CreateThread(0, 0, &test_report_win32::thread_runner, 0, 0, &l_Temp);
		}

		virtual void begin(size_t a_MaxTotal){
			m_MaxTotal = a_MaxTotal;
		}

		virtual void suite_end(const std::string &a_Name, size_t a_MaxTests){
			m_Progress += a_MaxTests;
		}

		virtual void end(){
			WaitForSingleObject(m_Id, INFINITE);
		}

		static DWORD WINAPI thread_runner(LPVOID){
			test_report_window *l_Window = new test_report_window();
			l_Window->start();
			while(true){
				l_Window->set_max_tests(m_MaxTotal);
				l_Window->set_progress((int)m_Progress);
				l_Window->run();
			}
			return 0;
		}
	private:
		HANDLE m_Id;

		// might need some locking :+
		static size_t m_MaxTotal;
		static size_t m_Progress;
	};
}
}